from django.core.validators import RegexValidator  # 进行数据校验的正则表达式
from django.core.exceptions import ValidationError  # 捕获表单提交的异常错误

from django.shortcuts import render, redirect
from app.models import Department, UserInfo, PrettyNumber

from django import forms  # 构建表单模型
from app.utils.pagination import Pagination  # 导入分页导航条

from django.utils.safestring import mark_safe  # 确保传输的字符串是安全的，用于传输拼接分页的html代码


# Create your views here.

def depart_list(request):
    """
    部门列表
    """
    data_list = Department.objects.all()
    return render(request, 'depart_list.html', {'queryset': data_list})


def depart_add(request):
    """
    新增部门
    """
    if request.method == 'GET':
        return render(request, 'depart_add.html')

    title = request.POST.get('title')

    Department.objects.create(title=title)
    return redirect('/depart/list')


def depart_delete(request):
    """
    删除部门
    """
    nid = request.GET.get('nid')
    Department.objects.filter(id=nid).delete()
    return redirect('/depart/list')


def depart_edit(request, nid):
    """
    编辑部门
    nid 用于接收前端传递过来的id,他的名字要和urls.py文件中定义的一样
    """
    if request.method == 'GET':  # 进入编辑页面
        row_object = Department.objects.filter(id=nid).first()
        return render(request, 'depart_edit.html', {'row_object': row_object})

    # 保存修改POST提交
    title = request.POST.get('title')
    Department.objects.filter(id=nid).update(title=title)
    return redirect('/depart/list')


def user_list(request):
    """
    用户列表
    """
    queryset = UserInfo.objects.all()

    page_object = Pagination(request, queryset,PAGE_SIZE=5) # 实例化分页导航条类
    page_queryset = page_object.page_queryset # 获得分完页的数据结果

    # 生成分页导航条
    page_nav = page_object.html()
    context = {
        'queryset': page_queryset,  # 分完页的数据结果
        'page_nav': page_nav  # 生成的页码导航条
    }
    return render(request, 'user_list.html', context)


def user_add(request):
    """
    添加用户 (原始实现方式)
    缺点：
     1.要重复前端form表单
     2.用户提交数据未校验
     3.前端输入错误没有提示
     4.关联的数据要手动获取，前端要循环渲染
    """
    if request.method == 'GET':
        content = {
            'gender': UserInfo.gender_choices,
            'depart': Department.objects.all()
        }

        return render(request, 'user_add.html', content)

    name = request.POST.get('name')
    password = request.POST.get('password')
    age = request.POST.get('age')
    account = request.POST.get('account')
    create_time = request.POST.get('create_time')
    depart_id = request.POST.get('depart')
    gender = request.POST.get('gender')

    UserInfo.objects.create(name=name, password=password, age=age,
                            account=account, create_time=create_time,
                            depart_id=depart_id, gender=gender)
    return redirect('/user/list')


class UserModelForm(forms.ModelForm):
    """
     用户类表单模型
     作用：用于定义渲染到前端的数据，设置校验规则等
     用法：
     用ModelForm来操作表记录
     1.基本用法：首先从django.forms导入ModelForm；
     2.编写一个自己的类，继承ModelForm；
     3.在新类里，设置元类Meta；
     4.在Meta中，设置model属性为你要关联的ORM模型，这里是UserInfo；
     5.在Meta中，设置fields属性为你要在表单中使用的字段列表；
     6.列表里的值，应该是ORM模型model中的字段名。
    """

    # 重新定义name字段的属性和校验规则
    name = forms.CharField(min_length=2, label='姓名')

    class Meta:
        model = UserInfo  # 指定需要显示的表名（在models.py中定义）

        # 指定要操作的字段名，是一个列表
        fields = ['name', 'age', 'gender', 'depart', 'create_time', 'account']

        # 给表单控件逐个添加属性
        # widgets = {
        #     'name': forms.TextInput(attrs={'class': 'form-control'}),
        #     'password': forms.PasswordInput(attrs={'class': 'form-control'}),
        #     'create_time': forms.DateInput(attrs={'class': 'form-control'}),
        # }

    # 给所有表单控件添加属性
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {"class": "form-control"}


class PrettyNumberForm(forms.ModelForm):
    """
    靓号类表单模型
    具体使用注解，见UserModelForm类
    """

    # 重新定义mobile字段的属性和校验规则 方式1
    mobile = forms.CharField(
        min_length=11,  # 最小长度
        label='号码',
        # 通过正则进行数据校验
        validators=[RegexValidator(r'^1[3-9]\d{9}$', '号码错误,长度不能超过11位')],
    )

    class Meta:
        model = PrettyNumber  # 指定需要显示的表名（在models.py中定义）
        # 指定要操作的字段名，是一个列表
        # fields = ['mobile', 'price', 'level', 'status']
        fields = '__all__'  # 渲染所有字段
        # exclude = ['level'] # 排除某个字段

    # 给所有表单控件添加属性
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {"class": "form-control"}

    # 对字段进行一些数据校验或操作 方式2
    # 名称必须是clean_字段名
    # 也称为钩子方法，更灵活，比如手机号是否已经存在...
    def clean_mobile(self):
        txt_value = self.cleaned_data['mobile']  # 获取到用户输入的字段值

        num_exist = PrettyNumber.objects.filter(mobile=txt_value).exists()
        if num_exist:
            raise ValidationError("号码已经存在")

        return txt_value


class PrettyNumberEditForm(forms.ModelForm):
    """
    靓号编辑类表单模型
    具体使用注解，见UserModelForm类
    """

    # 重新定义mobile字段的属性和校验规则 方式1
    mobile = forms.CharField(
        label='号码11',
        disabled=True,
    )

    class Meta:
        model = PrettyNumber  # 指定需要显示的表名（在models.py中定义）
        # 指定要操作的字段名，是一个列表
        # fields = ['mobile', 'price', 'level', 'status']
        fields = '__all__'  # 渲染所有字段

    # 给所有表单控件添加属性
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            field.widget.attrs = {"class": "form-control"}

    # 对字段进行一些数据校验或操作 方式2
    # 名称必须是clean_字段名
    # 也称为钩子方法，更灵活，比如手机号是否已经存在...
    def clean_mobile(self):
        txt_value = self.cleaned_data['mobile']  # 获取到用户输入的字段值

        # instance是编辑时传入的值，pk是id主键
        nid = self.instance.id
        # print(self.instance.mobile)

        # 修改时，要排除当前号码以外的其他数据
        # 也就是 where mobile=18995009009 and id!=2
        num_exist = PrettyNumber.objects.filter(mobile=txt_value).exclude(id=nid)
        if num_exist:
            raise ValidationError("号码已经存在")

        return txt_value


def user_add_modelform(request):
    """
    添加用户（通过Django ModelForm组件实现 最简便）
    """
    if request.method == 'GET':
        form = UserModelForm()  # 实例化类
        return render(request, 'user_add_modelform.html', {'form': form})

    # POST请求
    form = UserModelForm(data=request.POST)  # 拿到所有提交过来的数据
    if form.is_valid():  # 数据校验

        # 如果你想对数据表中的字段另外再传递值来保存，就用
        # form.instance.字段名 = '值'
        form.instance.password = '0000'  # 默认密码是0000

        form.save()  # 向 model = UserInfo 定义的表保存数据
        return redirect('/user/list/')
    else:
        # form中带了POST过来的请求
        return render(request, 'user_add_modelform.html', {'form': form})


def user_edit_modelform(request, nid):
    """
    用户信息修改
    nid 用于接收前端传递过来的id,他的名字要和urls.py文件中定义的一样
    """
    # 1.先查询到该条记录
    # 2.拿到POST请求过来的数据（data=request.POST），将将查询到数据对象传递给form（instance=row_data）
    row_data = UserInfo.objects.filter(id=nid).first()

    if request.method == 'GET':
        form = UserModelForm(instance=row_data)  # 将查询到的对象传递给form
        return render(request, 'user_edit_modelform.html', {'form': form})

    # POST请求
    form = UserModelForm(data=request.POST, instance=row_data)  # 拿到所有提交过来的数据
    if form.is_valid():  # 数据校验
        form.save()  # 向 model = UserInfo 定义的表保存数据
        return redirect('/user/list/')
    else:
        # form中带了POST过来的请求
        return render(request, 'user_edit_modelform.html', {'form': form})


def user_delete_modelform(request, nid):
    """
    用户信息删除
    nid 用于接收前端传递过来的id,他的名字要和urls.py文件中定义的一样
    """
    UserInfo.objects.filter(id=nid).delete()
    return redirect('/user/list/')


def pn_list(request):
    """
    靓号列表
    """


    # 第一次显示的时候，查询条件也就是data_dict为空，所以查询所有数据
    data_dict = {}
    search_data = request.GET.get('searchMobile', '')
    if search_data:
        data_dict['mobile__contains'] = search_data

    # ########## 分页准备数据阶段 ##########
    # 字典格式： queryset = {‘mobile__contains’: '9999'}
    # **data_dict传入字典，必须以**打头
    # order_by('-level') 倒序排列
    queryset = PrettyNumber.objects.filter(**data_dict).order_by('-level')

    page_object = Pagination(request, queryset) # 实例化分页导航条类
    page_queryset = page_object.page_queryset # 获得分完页的数据结果
    # ########## 分页数据准备结束 ##########

    # 生成分页导航条
    page_nav = page_object.html()

    # 把所有参数生成字典传递给前端
    context = {
        'search_data': search_data,
        'queryset': page_queryset,  # 分完页的数据结果
        'page_nav': page_nav  # 生成的页码导航条
    }

    return render(request, 'PrettyNumber_list.html', context)


def pn_add(request):
    """
    增加靓号
    """
    if request.method == 'GET':
        form = PrettyNumberForm()  # 实例化表单模型类
        return render(request, 'PrettyNumber_add_modelform.html', {'form': form})

    # POST请求
    form = PrettyNumberForm(data=request.POST)  # 拿到所有提交过来的数据
    if form.is_valid():  # 数据校验

        # 如果你想对数据表中的字段另外再传递值来保存，就用
        # form.instance.字段名 = '值'
        # form.instance.password = '0000'  # 默认密码是0000

        form.save()  # 向 model = PrettyNumber 定义的表保存数据
        return redirect('/PrettyNumber/list/')
    else:
        # form中带了POST过来的请求
        return render(request, 'PrettyNumber_add_modelform.html', {'form': form})


def pn_edit(request, nid):
    """
    靓号编辑
    """
    row_data = PrettyNumber.objects.filter(id=nid).first()

    if request.method == 'GET':
        form = PrettyNumberEditForm(instance=row_data)  # 将查询到的对象传递给form
        return render(request, 'PrettyNumber_edit_modelform.html', {'form': form})

    # POST请求
    form = PrettyNumberEditForm(data=request.POST, instance=row_data)  # 拿到所有提交过来的数据
    if form.is_valid():  # 数据校验
        form.save()  # 向 model = UserInfo 定义的表保存数据
        return redirect('/PrettyNumber/list/')
    else:
        # form中带了POST过来的请求
        return render(request, 'PrettyNumber_edit_modelform.html', {'form': form})


def pn_delete(request, nid):
    """
    靓号删除
    """
    PrettyNumber.objects.filter(id=nid).delete()
    return redirect('/PrettyNumber/list/')
